package com.blog.cloud.security.filter;

import com.blog.cloud.security.bo.UserInfo;
import com.blog.cloud.security.component.RedisTokenStore;
import com.blog.cloud.security.utils.JwtTokenUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import java.util.Objects;

@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private final RedisTokenStore redisTokenStore;

    @Override
    @SneakyThrows
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        String token = JwtTokenUtil.getToken(request);

        // 如果请求中没有认证信息则表示未登录状态
        if (StringUtils.isBlank(token)) {
            chain.doFilter(request, response);
            return;
        }

        // 如果有则开始认证过程
        UserInfo userInfo = redisTokenStore.getUserInfo(token);
        if (Objects.isNull(userInfo)) {
            chain.doFilter(request, response);
            return;
        }

        // 如果redis中有则表明登陆状态还有效，直接使用
        Authentication authentication = new UsernamePasswordAuthenticationToken(userInfo.getUsername(), userInfo.getPassword(),userInfo.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }
}

// 如果请求头带有token认证信息，则表明可能登陆过，因此在请求时先判断token有没有过期，如果redis中查不到信息，则过期，反之有效，然后从中取出用户认证信息,直接放入认证容器
// 因此在登录存放认证信息时也要存放认证对象才行
// spring security 默认的表单登录使用的是 UsernamePasswordAuthenticationFilter 过滤器，这里面进行了认证过程，自定义的并没有这个过滤器